package com.coffee.framework.security.filter;

import cn.hutool.core.util.CharsetUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.http.ContentType;
import cn.hutool.json.JSONUtil;
import com.coffee.common.Constants;
import com.coffee.common.bo.LoginUser;
import com.coffee.common.enums.GrantTypeEnum;
import com.coffee.common.result.R;
import com.coffee.common.result.ResultCode;
import com.coffee.framework.security.config.mobile.MobileCodeAuthenticationToken;
import com.coffee.framework.web.service.ITokenService;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Objects;

/**
 * token过滤器
 *
 * @author Kevin
 */
@Component
@Slf4j
public class AuthTokenFilter extends OncePerRequestFilter {

    private static final List<String> IGNORE_URL = Lists.newArrayList();

    static {
        IGNORE_URL.add("/api/");
        IGNORE_URL.add("/api/index");
        IGNORE_URL.add("/api/login");
        IGNORE_URL.add("/api/logout");
        IGNORE_URL.add("/api/common/**");
    }

    @Resource
    ITokenService tokenService;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String url = request.getRequestURI();
        //	校验请求的url是否在忽略鉴权的url中
        if (!checkUrl(url)) {
            String token = request.getHeader(Constants.HEADER_TOKEN);
            if (!tokenService.checkToken(token)) {
                log.info("请求访问：{}，请求未授权，无法访问系统资源", request.getRequestURI());
                response.setCharacterEncoding(CharsetUtil.UTF_8);
                ServletUtil.write(response, JSONUtil.toJsonStr(R.result(ResultCode.TOKEN_ERROR)), ContentType.JSON.toString());
                return;
            }
            LoginUser loginUser = tokenService.getUserByToken(token);
            if (Objects.nonNull(loginUser) && Objects.isNull(SecurityContextHolder.getContext().getAuthentication())) {
                if (loginUser.getGrantType().equals(GrantTypeEnum.USERNAME_PASSWORD.getCode())) {
                    UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
                    authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                    SecurityContextHolder.getContext().setAuthentication(authenticationToken);
                }
                if (loginUser.getGrantType().equals(GrantTypeEnum.MOBILE_CODE.getCode())) {
                    MobileCodeAuthenticationToken authenticationToken = new MobileCodeAuthenticationToken(loginUser, null, loginUser.getAuthorities());
                    authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                    SecurityContextHolder.getContext().setAuthentication(authenticationToken);
                }
            }
        }
        filterChain.doFilter(request, response);
    }

    private boolean checkUrl(String path) {
        AntPathMatcher antPathMatcher = new AntPathMatcher();
        return IGNORE_URL.stream().anyMatch(pattern -> antPathMatcher.match(pattern, path));
    }

}
